# -*- coding: utf-8 -*-

# created by mengqi on 2023/5/30

import cv2
import math


class App:
    flag_rect = False
    flag_line = False
    rect = (0, 0, 0, 0)
    line = (0, 0, 0, 0)
    min_dis_line = (0, 0, 0, 0)
    min_dis = -1
    start_rect_X = 0
    start_rect_Y = 0
    start_line_X = 0
    start_line_Y = 0
    img = None
    img2 = None

    def _on_mouse(self, event, x, y, flags, param):

        if event == cv2.EVENT_LBUTTONDOWN:
            self.flag_rect = True
            self.start_rect_X = x
            self.start_rect_Y = y
        elif event == cv2.EVENT_LBUTTONUP:
            self.flag_rect = False
            cv2.rectangle(self.img,
                          (self.start_rect_X, self.start_rect_Y),
                          (x, y),
                          (0, 0, 255),
                          3)
            self.rect = (min(self.start_rect_X, x), min(self.start_rect_Y, y),
                         abs(self.start_rect_X - x),
                         abs(self.start_rect_Y - y))
        elif event == cv2.EVENT_RBUTTONDOWN:
            self.flag_line = True
            self.start_line_X = x
            self.start_line_Y = y
        elif event == cv2.EVENT_RBUTTONUP:
            self.flag_line = False
            cv2.line(self.img, (self.start_line_X, self.start_line_Y), (x, y), (0, 0, 255), 3)
            self.line = (self.start_line_X, self.start_line_Y, x, y)
        elif event == cv2.EVENT_MOUSEMOVE:
            self.img = self.img2.copy()
            if self.flag_rect:
                cv2.rectangle(self.img,
                              (self.start_rect_X, self.start_rect_Y),
                              (x, y),
                              (255, 0, 0),
                              3)
            else:
                rect_x, rect_y, rect_w, rect_h = self.rect
                cv2.rectangle(self.img,
                              (rect_x, rect_y),
                              (rect_x + rect_w, rect_y + rect_h),
                              (0, 0, 255),
                              3)
            if self.flag_line:
                cv2.line(self.img, (self.start_line_X, self.start_line_Y), (x, y), (255, 0, 0), 3)
            else:
                line_start_x, line_start_y, line_end_x, line_end_y = self.line
                cv2.line(self.img, (line_start_x, line_start_y), (line_end_x, line_end_y), (0, 0, 255), 3)
            # 画最短距离线
            start_x, start_y, end_x, end_y = self.min_dis_line
            cv2.line(self.img, (start_x, start_y), (end_x, end_y), (0, 0, 255),
                     3)
            # 画文字
            if self.min_dis > 0:
                cv2.putText(self.img, "distance:" + str(self.min_dis), (500, 60), cv2.FONT_HERSHEY_SIMPLEX, 2,
                            (0, 0, 255),
                            5)

    # 两点距离
    def getdist_p2p(self, pa, pb):
        distance = math.pow((pa[0] - pb[0]), 2) + math.pow((pa[1] - pb[1]), 2)
        distance = math.sqrt(distance)
        return distance

    # 获取直线 与 点的垂足
    def get_foot(self, start_point, end_point, point_a):
        start_x, start_y = start_point
        end_x, end_y = end_point
        pa_x, pa_y = point_a

        p_foot = [0, 0]
        if start_point[0] == end_point[0]:
            p_foot[0] = start_point[0]
            p_foot[1] = point_a[1]
            return p_foot

        k = (end_y - start_y) * 1.0 / (end_x - start_x)
        a = k
        b = -1.0
        c = start_y - k * start_x
        p_foot[0] = int((b * b * pa_x - a * b * pa_y - a * c) / (a * a + b * b))
        p_foot[1] = int((a * a * pa_y - a * b * pa_x - b * c) / (a * a + b * b))

        return p_foot

    def run(self, img_path):
        cv2.namedWindow('input', cv2.WINDOW_NORMAL)
        cv2.setMouseCallback('input', self._on_mouse)

        self.img = cv2.imread(img_path)
        self.img2 = self.img.copy()

        while True:
            cv2.imshow('input', self.img)
            k = cv2.waitKey(100)
            if k == 27:
                break
            if k == ord('r'):
                self.rect = (0, 0, 0, 0)
                self.line = (0, 0, 0, 0)
                self.min_dis_line = (0, 0, 0, 0)
                self.min_dis = -1
                self.img = self.img2.copy()
            if k == ord('c'):
                line_start_x, line_start_y, line_end_x, line_end_y = self.line
                rect_x, rect_y, rect_w, rect_h = self.rect
                foot1_x, foot1_y = self.get_foot((rect_x, rect_y), (rect_x + rect_w, rect_y),
                                                 (line_start_x, line_start_y))

                dis1 = self.getdist_p2p((line_start_x, line_start_y), (foot1_x, foot1_y))
                foot2_x, foot2_y = self.get_foot((rect_x, rect_y), (rect_x + rect_w, rect_y),
                                                 (line_end_x, line_end_y))

                dis2 = self.getdist_p2p((line_end_x, line_end_y), (foot2_x, foot2_y))
                self.min_dis = dis1
                # 求最小距离
                if dis1 <= dis2:
                    self.min_dis_line = (line_start_x, line_start_y, foot1_x, foot1_y)
                else:
                    self.min_dis = dis2
                    self.min_dis_line = (line_end_x, line_end_y, foot2_x, foot2_y)
                print(self.min_dis)
                cv2.putText(self.img, "distance:" + str(self.min_dis), (500, 60), cv2.FONT_HERSHEY_SIMPLEX, 2,
                            (0, 0, 255),
                            5)

                start_x, start_y, end_x, end_y = self.min_dis_line
                cv2.line(self.img, (start_x, start_y), (end_x, end_y), (0, 0, 255),
                         3)
